/*!
 * 文件名称： driver_adc.c
 * 描    述： adc 驱动文件
 * 版本：     2023-12-03, V1.0
*/

/*
* GD32F303东方红开发板V1.0
* 淘宝商城：   https://juwo.taobao.com
* 技术交流：   https://www.gd32bbs.com/ask/
* 视频学习：   https://space.bilibili.com/475462605
* 微信公众号： gd32bbs
* Copyright    苏州聚沃电子科技有限公司
* 版权所有，盗版必究。
*/

#include "driver_public.h"
#include "driver_adc.h"

/*!
* 说明     ADC初始化，包括ADC时钟使能和功能配置
* 输入[1]  ADC：   ADC配置结构体指针
* 输入[2]  ADC_CH：ADC通道配置结构体指针
* 返回值   无
*/
void driver_adc_config(typdef_adc_ch_general *ADC,typdef_adc_ch_parameter *ADC_CH)
{	 
	uint8_t i;
	rcu_adc_clock_config(ADC->adc_psc); 					/*配置ADC时钟频率*/
	rcu_periph_clock_enable(ADC->rcu_adc); 				/*使能ADC时钟*/
    adc_deinit(ADC->adc_port);
    
	/*配置ADC相关IO口，先配置时钟，再将IO口设置为模拟输入*/
	for(i=0 ;i<ADC->ch_count; i++)
	{
		if(ADC_CH[i].adc_channel < ADC_CHANNEL_16)
		{
			rcu_periph_clock_enable(ADC_CH[i].rcu_port);
			gpio_init(ADC_CH[i].port, GPIO_MODE_AIN, ADC_CH[i].gpio_speed, ADC_CH[i].pin);					
		}
		else
		{
			adc_tempsensor_vrefint_enable();
		}
	}
	adc_mode_config(ADC->adc_mode);								/*配置ADC工作模式，如独立模式，规则并行模式等*/
	adc_special_function_config(ADC->adc_port, ADC_SCAN_MODE, ADC->adc_scan_function);	/*配置规则组的扫描模式和连续转换模式*/
	if(ADC->adc_channel_group == ADC_REGULAR_CHANNEL)
	{
		adc_special_function_config(ADC->adc_port, ADC_CONTINUOUS_MODE, ADC->adc_continuous_function);	
	}
	adc_data_alignment_config(ADC->adc_port, ADC_DATAALIGN_RIGHT);											/*选择数据右对齐*/
	adc_channel_length_config(ADC->adc_port, ADC->adc_channel_group, ADC->ch_count);		/*配置转换通道数*/
	if(ADC->adc_channel_group == ADC_REGULAR_CHANNEL)																		/*配置转换顺序*/
	{
		for(i = 0;i< ADC->ch_count;i++)
		{
			adc_regular_channel_config(ADC->adc_port, i, ADC_CH[i].adc_channel,ADC_CH[i].sample_time);
		}
	}
	else if(ADC->adc_channel_group == ADC_INSERTED_CHANNEL)
	{
		for(i = 0;i< ADC->ch_count;i++)
		{
			adc_inserted_channel_config(ADC->adc_port, i, ADC_CH[i].adc_channel,ADC_CH[i].sample_time);
		}	
	}
	/*选择触发源及使能外部触发模式*/
	adc_external_trigger_source_config(ADC->adc_port, ADC->adc_channel_group, ADC->trigger_source);	
	adc_external_trigger_config(ADC->adc_port, ADC->adc_channel_group, ENABLE);
	/*选择是否需要使用DMA*/
	if(ADC->DMA_mode == ENABLE)
	{
		adc_dma_mode_enable(ADC->adc_port);
	}
	 /*ADC的使能和自校准，ADC使能后需要经过一定的ADC_CLK后才能校准，本示例中直接使用1ms延时*/
	adc_enable(ADC->adc_port);
	delay_ms(1);
	adc_calibration_enable(ADC->adc_port);
}


/*!
* 说明     软件触发ADC转换函数
* 输入     ADC：ADC配置结构体指针
* 返回值   无
*/
void driver_adc_software_trigger_enable(typdef_adc_ch_general *ADC)
{
	adc_software_trigger_enable(ADC->adc_port, ADC->adc_channel_group);
}


/*!
* 说明     带DMA功能的ADC初始化，包括ADC时钟使能和功能配置
* 输入[1]  ADC：   ADC配置结构体指针
* 输入[2]  ADC_CH：ADC通道配置结构体指针
* 输入[3]  buffer：ADC数据缓存buffer
* 返回值   无
*/
void driver_adc_regular_ch_dma_config(typdef_adc_ch_general *ADC, typdef_adc_ch_parameter *ADC_CH,void *buffer)
{	
	dma_parameter_struct dma_data_parameter;
	rcu_periph_clock_enable(ADC->dma_parameter.rcu_dma);													/*DMA时钟开启*/
	dma_deinit(ADC->dma_parameter.dma_periph, ADC->dma_parameter.dma_channel);		/*DMA通道参数复位*/
	/*DMA源地址、目标地址、增量方式、传输位宽、传输方向、传输个数、优先级设置*/
	dma_data_parameter.periph_addr  = (uint32_t)(&ADC_RDATA(ADC->adc_port));
	dma_data_parameter.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;
	dma_data_parameter.memory_addr  = (uint32_t)(buffer);
	dma_data_parameter.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;
	if(ADC->adc_mode == ADC_DAUL_REGULAL_PARALLEL)
	{
		dma_data_parameter.periph_width = DMA_PERIPHERAL_WIDTH_32BIT;
		dma_data_parameter.memory_width = DMA_MEMORY_WIDTH_32BIT; 
	}
	else
	{
		dma_data_parameter.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
		dma_data_parameter.memory_width = DMA_MEMORY_WIDTH_16BIT; 
	}
	dma_data_parameter.direction    = DMA_PERIPHERAL_TO_MEMORY;
	dma_data_parameter.number       = ADC->dma_parameter.dma_number;
	dma_data_parameter.priority     = ADC->dma_parameter.dma_priority;
	dma_init(ADC->dma_parameter.dma_periph, ADC->dma_parameter.dma_channel, &dma_data_parameter);
	/*DMA循环模式设置*/
	if(ADC->dma_parameter.dma_circulation_mode == ENABLE)
	{
		dma_circulation_enable(ADC->dma_parameter.dma_periph, ADC->dma_parameter.dma_channel);
	}
	else
	{
		dma_circulation_disable(ADC->dma_parameter.dma_periph, ADC->dma_parameter.dma_channel);
	}
	dma_channel_enable(ADC->dma_parameter.dma_periph, ADC->dma_parameter.dma_channel);	/* 使能DMA */
	driver_adc_config(ADC,ADC_CH);																											/* ADC初始化 */
}


/*!
* 说明     轮训方式获取ADC值
* 输入[1]  ADC：   ADC配置结构体指针
* 输入[2]  ADC_CH：ADC通道配置结构体指针
* 返回值   无
*/
uint16_t driver_adc_transform_polling(typdef_adc_ch_general *ADC,typdef_adc_ch_parameter *ADC_CH)
{
	/*规则组采样*/
	if(ADC->adc_channel_group == ADC_REGULAR_CHANNEL)
	{
		adc_regular_channel_config(ADC->adc_port, 0, ADC_CH->adc_channel, ADC_CH->sample_time);			/*设置规则组需要采样的通道*/
		adc_software_trigger_enable(ADC->adc_port, ADC_REGULAR_CHANNEL);														/*软件触发规则组转换*/
		while(RESET == adc_flag_get(ADC->adc_port,ADC_FLAG_EOC));																		/*等待EOC置起*/
		adc_flag_clear(ADC->adc_port,ADC_FLAG_EOC);																									/*清除EOC标志位*/
		return ADC_RDATA(ADC->adc_port);																														/*将规则组转换结果作为返回值*/
		
	}
	/*注入组采样*/
	else if(ADC->adc_channel_group == ADC_INSERTED_CHANNEL)
	{
		adc_inserted_channel_config(ADC->adc_port, 0, ADC_CH->adc_channel, ADC_CH->sample_time);		/*设置注入组需要采样的通道*/
		adc_software_trigger_enable(ADC->adc_port, ADC_INSERTED_CHANNEL);														/*软件触发注入组转换*/
		while(RESET == adc_flag_get(ADC->adc_port,ADC_FLAG_EOIC));																	/*等待EOIC置起 */
		adc_flag_clear(ADC->adc_port,ADC_FLAG_EOIC);																								/*清除EOIC标志位*/
		return ADC_IDATA0(ADC->adc_port);																														/*将注入组转换结果作为返回值*/
	}
	return 0;
}

/*!
* 说明     ADC中断处理函数
* 输入[1]  ADC：   ADC配置结构体指针
* 输入[2]  buffer：ADC数据缓存buffer
* 返回值   无
*/

void driver_adc_int_handler(typdef_adc_ch_general *ADC,void *buffer)
{
	uint8_t i;
  uint32_t buff_addres=(uint32_t)(buffer);
	if(ADC->adc_channel_group == ADC_REGULAR_CHANNEL)
	{
		if(SET == adc_interrupt_flag_get(ADC->adc_port,ADC_INT_FLAG_EOC))
		{
			adc_interrupt_flag_clear(ADC->adc_port,ADC_INT_FLAG_EOC);
			if(ADC->adc_mode == ADC_DAUL_REGULAL_PARALLEL)
			{
				REG32(buffer) = (uint32_t)(ADC_RDATA(ADC->adc_port));
			}
			else
			{
				REG16(buffer) = (uint16_t)(ADC_RDATA(ADC->adc_port));
			}
			
		}
	}
	else if(ADC->adc_channel_group == ADC_INSERTED_CHANNEL)
	{
		if(SET == adc_interrupt_flag_get(ADC->adc_port,ADC_INT_FLAG_EOIC))
		{
			adc_interrupt_flag_clear(ADC->adc_port,ADC_INT_FLAG_EOIC);
			if(ADC->adc_mode == ADC_DAUL_INSERTED_PARALLEL)
			{
				for(i = 0; i<ADC->ch_count ; i++)
				{
					REG32(buff_addres) = REG32((ADC->adc_port) + 0x3C+(i*4));
					buff_addres += 4;
				}
			}
			else
			{
				for(i = 0; i<ADC->ch_count ; i++)
				{
					REG16(buff_addres) = REG32((ADC->adc_port) + 0x3C+(i*4));
					buff_addres += 2;
				}
			}
		}
	}
}

/*!
* 说明     ADC DMA中断处理函数
* 输入[1]  ADC：ADC配置结构体指针
* 返回值   无
*/
void driver_adc_dma_int_handler(typdef_adc_ch_general *ADC)
{
	if(SET == dma_interrupt_flag_get(ADC->dma_parameter.dma_periph,ADC->dma_parameter.dma_channel,DMA_INT_FLAG_FTF))
	{
		dma_interrupt_flag_clear(ADC->dma_parameter.dma_periph,ADC->dma_parameter.dma_channel,DMA_INT_FLAG_FTF);
	}
}


/*!
* 说明     ADC中断使能函数
* 输入[1]  ADC：   ADC配置结构体指针
* 返回值   无
*/
void ADC_int_enable(typdef_adc_ch_general *ADC)
{
	/*规则组中断使能*/
	if(ADC->adc_channel_group == ADC_REGULAR_CHANNEL)
	{
		adc_interrupt_enable(ADC->adc_port,ADC_INT_EOC);
		adc_interrupt_flag_clear(ADC->adc_port,ADC_INT_EOC);
	}
	/*注入组中断使能*/
	else if(ADC->adc_channel_group == ADC_INSERTED_CHANNEL)
	{
		adc_interrupt_enable(ADC->adc_port,ADC_INT_EOIC);
		adc_interrupt_flag_clear(ADC->adc_port,ADC_INT_EOIC);
	}	
}


/*!
* 说明     ADC DMA使能函数
* 输入[1]  ADC：   ADC配置结构体指针
* 返回值   无
*/
void ADC_dma_int_enable(typdef_adc_ch_general *ADC)
{
	dma_interrupt_enable(ADC->dma_parameter.dma_periph,ADC->dma_parameter.dma_channel,DMA_INT_FTF);	
}

